package product

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/product/model"
	"mall/service/product/rpc/internal/svc"
	"mall/service/product/rpc/types/product"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetProductListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductListLogic {
	return &GetProductListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *GetProductListLogic) GetProductList(in *product.BaseListReq) (*product.ProductListResp, error) {
	// logrus.Info(fmt.Sprintf("GetProductList BaseListReq: %+v", in))
	// Limit:10  Preload:"product:Id,Title,Slug;productMeta:mediaId,mediaUrl,retailPriceMin,hotSell;productRelationship:PerfumeId,PerfumeName,PerfumeSlug,BrandId,BrandName,BrandSlug"  EagerLoad:"product:productMeta,productRelationship"  Filter:"virtual,equalTo:0;Status,equalTo:1"  PreFilterEntity:"productMeta"  PreFilter:"recommend,equalTo:1"  VisitorId:0  PlatformId:1
	// Limit:10  Preload:\"product:Id,Title,Slug;productMeta:mediaUrl,retailPriceMin,hotSell;productMedia:Uid,Url,altText,metaData\"  EagerLoad:\"product:productMeta,productMedia\"  Filter:\"virtual,equalTo:0;Status,equalTo:1\"  Search:\"宝格丽\\xbf'\\xbf''\\\"'\\\"\\\\\\\\\\\\\\r\\n##\"  VisitorId:10039  PlatformId:1
	// Limit:10  Preload:\"product:Id,Title,Slug;productMeta:mediaUrl,retailPriceMin,hotSell;productMedia:Uid,Url,altText,metaData\"  EagerLoad:\"product:productMeta,productMedia\"  Filter:\"virtual,equalTo:0;Status,equalTo:1\"  Search:\"aaaa'\\xbf'\"  VisitorId:10039  PlatformId:1
	// Limit:10  Preload:\"product:Id,Title,Slug;productMeta:mediaUrl,retailPriceMin,hotSell;productMedia:Uid,Url,altText,metaData\"  EagerLoad:\"product:productMeta,productMedia\"  Filter:\"virtual,equalTo:0;Status,equalTo:1\"  Search:\"\\xbf'\\xbf''\\\"'\\\"\\\\\\\\\\\\\\r\\n##\"  VisitorId:10039  PlatformId:1

	if (in.Filter == nil || len(*in.Filter) == 0) && (in.PreFilter == nil || len(*in.PreFilter) == 0) {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)

	// logrus.Info(fmt.Sprintf("GetProductList preloadMap: %+v", preloadMap))
	// map[product:[Id ParentId Title Slug] productMeta:[mediaId mediaUrl] productRelationship:[PerfumeId PerfumeName PerfumeSlug BrandId BrandName BrandSlug] productTerm:[Id Name Slug ParentId] productVariation:[Id GemPrice RetailPrice Weight Status] productVariationMeta:[stock mediaId mediaUrl sku]]
	// map[product:[Id Title Slug] productMeta:[mediaId mediaUrl retailPriceMin hotSell] productRelationship:[PerfumeId PerfumeName PerfumeSlug BrandId BrandName BrandSlug]]

	// logrus.Info(fmt.Sprintf("GetProductList eagerLoadMap: %+v", eagerLoadMap))
	// map[product:[productVariation productVariationMeta productMeta productTerm productRelationship]]
	// map[product:[productMeta]]

	productEntityName := model.RpcEntityNames.Product
	if _, ok := model.RpcEntityPreloadMap[productEntityName]; !ok {
		return &product.ProductListResp{}, nil
	}

	productRepositoryName := model.RepositoryNames.Product
	columnMap, ok := model.RepositoryPreloadMap[productRepositoryName]
	if !ok {
		return &product.ProductListResp{}, nil
	}

	var count int64
	var err error
	var preFilteredByTerm bool
	var preFilteredByEntry bool
	var preFilteredByVariation bool
	var termRelations []*model.ProductTermRelationship
	var entryRelations []*model.ProductKnowledgeBaseRelationship
	var variations []*model.ProductVariation
	var pids []any
	if in.PreFilterEntity != nil && in.PreFilter != nil {
		productTermEntityName := model.RpcEntityNames.ProductTerm
		productRelationshipEntityName := model.RpcEntityNames.ProductRelationship
		productVariationEntityName := model.RpcEntityNames.ProductVariation
		productMetaEntityName := model.RpcEntityNames.ProductMeta
		switch *in.PreFilterEntity {
		case productTermEntityName:
			if _, ok := model.RpcEntityPreloadMap[productTermEntityName]; ok {
				productTermRepositoryName := model.RepositoryNames.ProductTerm
				if preColumnMap, ok := model.RepositoryPreloadMap[productTermRepositoryName]; ok {
					filterMap := modelx.ParseFilter(in.PreFilter, preColumnMap)
					// logrus.Info(fmt.Sprintf("GetProductList preFilterMap: %+v", filterMap))
					// map[term_id:map[equalTo:[12]]]
					if filterMap == nil {
						return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
					}

					orderBy := modelx.ParseSorter(in.PreSorter, preColumnMap)
					// logrus.Info(fmt.Sprintf("GetProductList preOrderBy: %s", orderBy))
					//

					res, _, err := l.svcCtx.CurrentProduct.GetRelationshipList(l.ctx, model.M{
						"offset":  in.Offset,
						"limit":   in.Limit,
						"orderBy": orderBy,
					}, 2, filterMap)
					if err != nil {
						return nil, err
					}

					if len(res) == 0 {
						return &product.ProductListResp{}, nil
					}

					pidMap := make(map[uint64]struct{})
					preFilteredByTerm = true
					count = 0
					for _, v := range res {
						if _, ok := pidMap[v.ObjectID]; ok { // 防重复
							continue
						}

						pidMap[v.ObjectID] = struct{}{}
						pids = append(pids, v.ObjectID)
						count += 1
						termRelations = append(termRelations, v)
					}
				}
			}
		case productRelationshipEntityName:
			if _, ok := model.RpcEntityPreloadMap[productRelationshipEntityName]; ok {
				productRelationshipRepositoryName := model.RepositoryNames.ProductRelationship
				if preColumnMap, ok := model.RepositoryPreloadMap[productRelationshipRepositoryName]; ok {
					filterMap := modelx.ParseFilter(in.PreFilter, preColumnMap)
					// logrus.Info(fmt.Sprintf("GetProductList preFilterMap: %+v", filterMap))
					// map[to_entry_group_id:map[in:[44089]]]
					if filterMap == nil {
						return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
					}

					orderBy := modelx.ParseSorter(in.PreSorter, preColumnMap)
					// logrus.Info(fmt.Sprintf("GetProductList preOrderBy: %s", orderBy))
					//

					res, _, err := l.svcCtx.CurrentProduct.GetEntryList(l.ctx, model.M{
						"offset":  in.Offset,
						"limit":   in.Limit,
						"orderBy": orderBy,
					}, 2, filterMap)
					if err != nil {
						return nil, err
					}

					if len(res) == 0 {
						return &product.ProductListResp{}, nil
					}

					pidMap := make(map[uint64]struct{})
					preFilteredByEntry = true
					count = 0
					for _, v := range res {
						if _, ok := pidMap[v.ProductID]; ok { // 防重复
							continue
						}

						pidMap[v.ProductID] = struct{}{}
						pids = append(pids, v.ProductID)
						count += 1
						entryRelations = append(entryRelations, v)
					}
				}
			}
		case productVariationEntityName:
			if _, ok := model.RpcEntityPreloadMap[productVariationEntityName]; ok {
				productVariationRepositoryName := model.RepositoryNames.ProductVariation
				if preColumnMap, ok := model.RepositoryPreloadMap[productVariationRepositoryName]; ok {
					filterMap := modelx.ParseFilter(in.PreFilter, preColumnMap)
					// logrus.Info(fmt.Sprintf("GetProductList preFilterMap: %+v", filterMap))
					// map[product_variation_id:map[in:[18 13]]]
					if filterMap == nil {
						return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
					}

					orderBy := modelx.ParseSorter(in.PreSorter, preColumnMap)
					logrus.Info(fmt.Sprintf("GetProductList preOrderBy: %s", orderBy))
					res, _, err := l.svcCtx.CurrentProduct.GetVariationList(l.ctx, model.M{
						"offset":  in.Offset,
						"limit":   in.Limit,
						"orderBy": orderBy,
					}, 2, filterMap)
					if err != nil {
						return nil, err
					}

					if len(res) == 0 {
						return &product.ProductListResp{}, nil
					}

					pidMap := make(map[uint64]struct{})
					preFilteredByVariation = true
					count = 0
					for _, v := range res {
						if _, ok := pidMap[v.ProductVariationID]; ok { // 防重复
							continue
						}

						pidMap[v.ProductVariationID] = struct{}{}
						pids = append(pids, v.ProductID)
						count += 1
						variations = append(variations, v)
					}
				}
			}
		case productMetaEntityName:
			if entitySettingMap, ok := model.RpcEntityPreloadMap[productMetaEntityName]; ok {
				productMetaRepositoryName := model.RepositoryNames.ProductMeta
				if preColumnMap, ok := model.RepositoryPreloadMap[productMetaRepositoryName]; ok {
					fieldMap := make(map[string]string)
					for field, fieldSetting := range entitySettingMap {
						if len(fieldSetting.Name) > 0 {
							fieldMap[field] = fieldSetting.Name
						}
					}

					filterMap := modelx.ParseMetaFilter(in.PreFilter, preColumnMap, fieldMap)
					// in.PreFilter    recommend,equalTo:1
					// logrus.Info(fmt.Sprintf("GetProductList preColumnMap: %+v", preColumnMap))
					// map[Id:meta_id MetaKey:meta_key MetaValue:meta_value ProductId:product_id]
					// logrus.Info(fmt.Sprintf("GetProductList fieldMap: %+v", fieldMap))
					// map[averageRating:_average_rating recommend:_recommend]
					// logrus.Info(fmt.Sprintf("GetProductList preFilterMap: %+v", filterMap))
					// map[meta_key:map[equalTo:[_recommend]] meta_value:map[equalTo:[1]]]
					if filterMap == nil {
						return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
					}

					orderBy := modelx.ParseSorter(in.PreSorter, preColumnMap)
					// logrus.Info(fmt.Sprintf("GetProductList preOrderBy: %s", orderBy))
					if len(orderBy) == 0 {
						orderBy = model.ProductMetumColumns.MetaID + " DESC"
					}

					res, _, err := l.svcCtx.CurrentProduct.GetMeta(l.ctx, model.M{
						"offset":  in.Offset,
						"limit":   in.Limit,
						"orderBy": orderBy,
					}, 2, filterMap)
					if err != nil {
						return nil, err
					}

					if len(res) == 0 {
						return &product.ProductListResp{}, nil
					}

					pidMap := make(map[uint64]struct{})
					count = 0
					for _, v := range res {
						if _, ok := pidMap[v.ProductID]; ok { // 防重复
							continue
						}

						pidMap[v.ProductID] = struct{}{}
						pids = append(pids, v.ProductID)
						count += 1
					}
				}
			}
		}
	}

	var selectCols []string
	if preloadFields, ok := preloadMap[productEntityName]; ok {
		selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
	}

	filterMap := modelx.ParseFilter(in.Filter, columnMap)
	// logrus.Info(fmt.Sprintf("GetProductList filterMap: %+v", filterMap))
	// map[status:map[equalTo:[1]] virtual_type:map[equalTo:[0]]]
	if filterMap == nil {
		if len(pids) == 0 {
			return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
		}

		filterMap = make(map[string]map[string][]any)
		filterMap[model.ProductProductColumns.Status] = map[string][]any{
			"equalTo": {globalkey.StatusEnabled},
		}
		filterMap[model.ProductProductColumns.VirtualType] = map[string][]any{
			"equalTo": {globalkey.ProductTypePhysical},
		}
	}

	orderBy := modelx.ParseSorter(in.Sorter, columnMap)
	// logrus.Info(fmt.Sprintf("GetProductList orderBy: %s", orderBy))

	var keyword string
	if in.Search != nil && len(strings.TrimSpace(*in.Search)) > 0 {
		keyword = strings.TrimSpace(*in.Search)
	}

	var res []*model.ProductProduct
	if len(pids) > 0 {
		filterMap[model.ProductProductColumns.ID] = map[string][]any{
			"in": pids,
		}
		res, _, err = l.svcCtx.CurrentProduct.GetList(l.ctx, model.M{
			"search":  keyword,
			"orderBy": orderBy,
			"select":  strings.Join(selectCols, ","),
		}, -1, filterMap)
	} else {
		res, count, err = l.svcCtx.CurrentProduct.GetList(l.ctx, model.M{
			"offset":  in.Offset,
			"limit":   in.Limit,
			"search":  keyword,
			"orderBy": orderBy,
			"select":  strings.Join(selectCols, ","),
		}, 2, filterMap)
	}
	if err != nil {
		return nil, err
	}

	hasNextPage, hasPreviousPage := modelx.ParseCount(count)
	resp := &product.ProductListResp{
		HasNextPage:     &hasNextPage,
		HasPreviousPage: &hasPreviousPage,
	}

	var total int64
	if len(res) > 0 {
		var ids []any
		for _, v := range res {
			ids = append(ids, v.ID)
		}

		subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
		if eagerLoadEntities, ok := eagerLoadMap[productEntityName]; ok {
			for _, entity := range eagerLoadEntities {
				if entity == "total" {
					_, total, err = l.svcCtx.CurrentProduct.GetList(l.ctx, model.M{}, 0, filterMap)
					if err != nil {
						total = 0
					}
					continue
				}

				if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
					subEntitySettingMap[entity] = entitySettingMap
				}
			}
		}

		idCategoryMap := make(map[uint64][]*product.TermInfo)
		idTagMap := make(map[uint64][]*product.TermInfo)
		productTermEntityName := model.RpcEntityNames.ProductTerm
		if _, ok := subEntitySettingMap[productTermEntityName]; ok {
			productTermRepositoryName := model.RepositoryNames.ProductTerm
			subPreloadFields, hasSubPreloadFields := preloadMap[productTermEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[productTermRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				if !preFilteredByTerm {
					subFilterMap := make(map[string]map[string][]any)
					subFilterMap[model.ProductTermRelationshipColumns.ObjectID] = map[string][]any{
						"in": ids,
					}
					subFilterMap[model.ProductTermRelationshipColumns.ObjectType] = map[string][]any{
						"equalTo": {globalkey.PostTypeProduct},
					}
					termRelations, _, err = l.svcCtx.CurrentProduct.GetRelationshipList(l.ctx, model.M{
						"select": model.ProductTermRelationshipColumns.TermID + "," + model.ProductTermRelationshipColumns.ObjectID,
					}, -1, subFilterMap)
					if err != nil {
						return nil, err
					}
				}

				if len(termRelations) > 0 {
					tidMap := make(map[uint64][]uint64) // 保存term对应的pids(ObjectID)
					var tids []any
					for _, v := range termRelations {
						if _, ok := tidMap[v.TermID]; !ok {
							tids = append(tids, v.TermID)
						}
						tidMap[v.TermID] = append(tidMap[v.TermID], v.ObjectID)
					}

					subFilterMap := make(map[string]map[string][]any)
					subFilterMap[model.ProductTermColumns.TermID] = map[string][]any{
						"in": tids,
					}
					subSelectCols = append(subSelectCols, model.ProductTermColumns.Taxonomy) // 必须获取以区分category及tag
					termList, _, err := l.svcCtx.ProductTerm.GetList(l.ctx, model.M{
						"select": strings.Join(subSelectCols, ","),
					}, -1, subFilterMap)
					if err != nil {
						return nil, err
					}

					for _, v := range termList {
						if oids, ok := tidMap[v.TermID]; ok {
							oidMap := make(map[uint64]struct{})
							for _, oid := range oids {
								if _, ok := oidMap[oid]; !ok {
									switch int32(v.Taxonomy) {
									case globalkey.TermTaxonomyCategory:
										idCategoryMap[oid] = append(idCategoryMap[oid], &product.TermInfo{
											Id:       &v.TermID,
											Name:     &v.Name,
											Slug:     &v.Slug,
											ParentId: &v.ParentID,
										})
									case globalkey.TermTaxonomyProductTag:
										idTagMap[oid] = append(idTagMap[oid], &product.TermInfo{
											Id:   &v.TermID,
											Name: &v.Name,
											Slug: &v.Slug,
										})
									}
									oidMap[oid] = struct{}{}
								}
							}
						}
					}
				}
			}
		}

		idEntryMap := make(map[uint64][]*product.EntryInfo)
		productRelationshipEntityName := model.RpcEntityNames.ProductRelationship
		if _, ok := subEntitySettingMap[productRelationshipEntityName]; ok {
			productRelationshipRepositoryName := model.RepositoryNames.ProductRelationship
			subPreloadFields, hasSubPreloadFields := preloadMap[productRelationshipEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[productRelationshipRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				if !preFilteredByEntry {
					subFilterMap := make(map[string]map[string][]any)
					subFilterMap[model.ProductKnowledgeBaseRelationshipColumns.ProductID] = map[string][]any{
						"in": ids,
					}
					subSelectCols = append(subSelectCols, model.ProductKnowledgeBaseRelationshipColumns.ProductID)
					entryRelations, _, err = l.svcCtx.CurrentProduct.GetEntryList(l.ctx, model.M{
						"select": strings.Join(subSelectCols, ","),
					}, -1, subFilterMap)
					if err != nil {
						return nil, err
					}
				}

				if len(entryRelations) > 0 {
					for _, v := range entryRelations {
						if v.ToEntryID > 0 {
							idEntryMap[v.ProductID] = append(idEntryMap[v.ProductID], &product.EntryInfo{
								Id:   &v.ToEntryID,
								Key:  pointy.GetPointer(globalkey.ProductRelationNamePerfume),
								Name: &v.ToEntryName,
								Slug: &v.ToEntrySlug,
							})
						}
						if v.ToEntryGroupID > 0 {
							idEntryMap[v.ProductID] = append(idEntryMap[v.ProductID], &product.EntryInfo{
								Id:   &v.ToEntryGroupID,
								Key:  pointy.GetPointer(globalkey.ProductRelationNameBrand),
								Name: &v.ToEntryGroupName,
								Slug: &v.ToEntryGroupSlug,
							})
						}
					}
				}
			}
		}

		idAttrMap := make(map[uint64][]*product.ProductAttrInfo)
		idSpecMap := make(map[uint64][]*product.ProductAttrInfo)
		productAttributeEntityName := model.RpcEntityNames.ProductAttribute
		if _, ok := subEntitySettingMap[productAttributeEntityName]; ok {
			productAttributeRepositoryName := model.RepositoryNames.ProductAttribute
			subPreloadFields, hasSubPreloadFields := preloadMap[productAttributeEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[productAttributeRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.ProductAttributeColumns.ProductID] = map[string][]any{
					"in": ids,
				}
				subSelectCols = append(subSelectCols, model.ProductAttributeColumns.ProductID)
				var orderBy string = model.ProductAttributeColumns.ProductAttributeID
				list, _, err := l.svcCtx.CurrentProduct.GetAttributeList(l.ctx, model.M{
					"orderBy": orderBy,
					"select":  strings.Join(subSelectCols, ","),
				}, -1, subFilterMap)
				if err != nil {
					return nil, err
				}

				if len(list) > 0 {
					var ids []any
					for _, v := range list {
						ids = append(ids, v.ProductAttributeID)
					}

					optionFilterMap := make(map[string]map[string][]any)
					optionFilterMap[model.ProductAttributeOptionColumns.AttributeID] = map[string][]any{
						"in": ids,
					}
					// optionFilterMap[model.ProductAttributeOptionColumns.Status] = map[string][]any{
					// 	"equalTo": {globalkey.StatusEnabled},
					// }
					optionList, _, err := l.svcCtx.CurrentProduct.GetAttributeOptionList(l.ctx, model.M{}, -1, optionFilterMap)
					if err != nil {
						return nil, err
					}

					attrOptMap := make(map[uint64][]*product.ProductAttrOptInfo)
					if len(optionList) > 0 {
						for _, v := range optionList {
							attrOptMap[v.AttributeID] = append(attrOptMap[v.AttributeID], &product.ProductAttrOptInfo{
								Id:       &v.OptionID,
								Label:    &v.Name,
								Slug:     &v.Slug,
								MediaId:  pointy.GetPointer(strconv.FormatUint(v.ThumbnailID, 10)),
								MediaUrl: &v.ThumbnailURL,
							})
						}
					}

					for _, v := range list {
						if opts, ok := attrOptMap[v.ProductAttributeID]; ok {
							if v.IsVariationAttribute > 0 {
								idSpecMap[v.ProductID] = append(idSpecMap[v.ProductID], &product.ProductAttrInfo{
									Id:       &v.ProductAttributeID,
									Label:    &v.Name,
									Slug:     &v.Slug,
									HasMedia: pointy.GetPointer(uint32(v.HasImage)),
									Options:  opts,
								})
							} else {
								idAttrMap[v.ProductID] = append(idAttrMap[v.ProductID], &product.ProductAttrInfo{
									Id:       &v.ProductAttributeID,
									Label:    &v.Name,
									Slug:     &v.Slug,
									HasMedia: pointy.GetPointer(uint32(v.HasImage)),
									Options:  opts,
								})
							}
						}
					}
				}
			}
		}

		idVariationMap := make(map[uint64][]*product.ProductVariationInfo)
		productVariationEntityName := model.RpcEntityNames.ProductVariation
		if _, ok := subEntitySettingMap[productVariationEntityName]; ok {
			productVariationRepositoryName := model.RepositoryNames.ProductVariation
			subPreloadFields, hasSubPreloadFields := preloadMap[productVariationEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[productVariationRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				if !preFilteredByVariation {
					subFilterMap := make(map[string]map[string][]any)
					subFilterMap[model.ProductVariationColumns.ProductID] = map[string][]any{
						"in": ids,
					}
					subFilterMap[model.ProductVariationColumns.Status] = map[string][]any{
						"equalTo": {globalkey.StatusEnabled},
					}
					subSelectCols = append(subSelectCols, model.ProductVariationColumns.ProductID)
					var orderBy string = model.ProductVariationColumns.ProductVariationID
					variations, _, err = l.svcCtx.CurrentProduct.GetVariationList(l.ctx, model.M{
						"orderBy": orderBy,
						"select":  strings.Join(subSelectCols, ","),
					}, -1, subFilterMap)
					if err != nil {
						return nil, err
					}
				}

				if len(variations) > 0 {
					var ids []any
					for _, v := range variations {
						ids = append(ids, v.ProductVariationID)
					}

					productVariationMetaEntityName := model.RpcEntityNames.ProductVariationMeta
					idVariationMetaMap := make(map[uint64]map[string]*model.ProductVariationMetum)
					if entitySettingMap, ok := subEntitySettingMap[productVariationMetaEntityName]; ok {
						if subPreloadFields, ok := preloadMap[productVariationMetaEntityName]; ok {
							var metaKeys []any
							metaKeyMap := make(map[string]string)
							for _, field := range subPreloadFields {
								if fieldSetting, ok := entitySettingMap[field]; ok && len(fieldSetting.Name) > 0 {
									metaKeys = append(metaKeys, fieldSetting.Name)
									metaKeyMap[fieldSetting.Name] = field
								}
							}
							if len(metaKeys) > 0 {
								subFilterMap := make(map[string]map[string][]any)
								subFilterMap[model.ProductVariationMetumColumns.ProductID] = map[string][]any{
									"in": ids,
								}
								subFilterMap[model.ProductVariationMetumColumns.MetaKey] = map[string][]any{
									"in": metaKeys,
								}
								meta, _, err := l.svcCtx.CurrentProduct.GetVariationMeta(l.ctx, model.M{
									"orderBy": model.ProductVariationMetumColumns.MetaID + " DESC",
								}, -1, subFilterMap)
								if err != nil && err != model.ErrNotFound {
									return nil, err
								}

								if len(meta) > 0 {
									for _, v := range meta {
										key := v.MetaKey
										if len(key) > 0 && v.MetaValue.Valid {
											if field, ok := metaKeyMap[key]; ok {
												if _, ok := idVariationMetaMap[v.ProductID]; !ok {
													idVariationMetaMap[v.ProductID] = make(map[string]*model.ProductVariationMetum)
												}
												idVariationMetaMap[v.ProductID][field] = v
											}
										}
									}
								}
							}
						}
					}

					for _, v := range variations {
						var skuKey *string
						var skuStr *string
						var mediaId *string
						var mediaUrl *string
						var inventory *uint32
						var saleCount uint32
						if metaMap, ok := idVariationMetaMap[v.ProductVariationID]; ok {
							for key, metum := range metaMap {
								val := metum.MetaValue.String
								switch key {
								case "stock":
									if i, err := strconv.ParseInt(val, 10, 32); err == nil {
										inventory = pointy.GetPointer(uint32(i))
									}
								case "saleCount": // 预设的总销量
									if i, err := strconv.ParseInt(val, 10, 32); err == nil {
										saleCount += uint32(i)
									}
								case "totalSaleCount": // 实际的总销量
									if i, err := strconv.ParseInt(val, 10, 32); err == nil {
										saleCount += uint32(i)
									}
								case "mediaId":
									mediaId = pointy.GetPointer(val)
								case "mediaUrl":
									mediaUrl = pointy.GetPointer(val)
								case "sku":
									skuStr = pointy.GetPointer(val)
								case "skuKey":
									skuKey = pointy.GetPointer(val)
								}
							}
						}

						idVariationMap[v.ProductID] = append(idVariationMap[v.ProductID], &product.ProductVariationInfo{
							Id:           &v.ProductVariationID,
							Key:          skuKey,
							Label:        skuStr,
							GemPrice:     pointy.GetPointer(moneyx.FormatGem(int64(v.GemPrice))),
							RetailPrice:  pointy.GetPointer(moneyx.FormatAmount(int64(v.RetailPrice))),
							CounterPrice: pointy.GetPointer(moneyx.FormatAmount(int64(v.CounterPrice))),
							Weight:       pointy.GetPointer(moneyx.FormatWeight(int64(v.Weight))),
							SkuCode:      &v.SkuCode,
							MediaId:      mediaId,
							MediaUrl:     mediaUrl,
							Inventory:    inventory,
							SaleCount:    pointy.GetPointer(saleCount),
							SkuType:      pointy.GetPointer(uint32(v.SkuType)), // Todo: 添加注释
							Status:       pointy.GetPointer(uint32(v.Status)),
						})
					}
				}
			}
		}

		idMetaMap := make(map[uint64][]*product.MetaInfo)
		productMetaEntityName := model.RpcEntityNames.ProductMeta
		if entitySettingMap, ok := subEntitySettingMap[productMetaEntityName]; ok {
			if subPreloadFields, ok := preloadMap[productMetaEntityName]; ok {
				var metaKeys []any
				metaKeyMap := make(map[string]string)
				for _, field := range subPreloadFields {
					if fieldSetting, ok := entitySettingMap[field]; ok && len(fieldSetting.Name) > 0 {
						metaKeys = append(metaKeys, fieldSetting.Name)
						metaKeyMap[fieldSetting.Name] = field
					}
				}
				if len(metaKeys) > 0 {
					subFilterMap := make(map[string]map[string][]any)
					subFilterMap[model.ProductMetumColumns.ProductID] = map[string][]any{
						"in": ids,
					}
					subFilterMap[model.ProductMetumColumns.MetaKey] = map[string][]any{
						"in": metaKeys,
					}
					var orderBy string = model.ProductMetumColumns.MetaID + " DESC"
					list, _, err := l.svcCtx.CurrentProduct.GetMeta(l.ctx, model.M{
						"orderBy": orderBy,
					}, -1, subFilterMap)
					if err != nil && err != model.ErrNotFound {
						return nil, err
					}

					if len(list) > 0 {
						keyMap := make(map[uint64]map[string]struct{})
						for _, v := range list {
							key := v.MetaKey
							if len(key) > 0 && v.MetaValue.Valid {
								if subMap, ok := keyMap[v.MetaID]; ok { // 防重复
									if _, ok := subMap[key]; ok {
										continue
									}

									keyMap[v.MetaID][v.MetaKey] = struct{}{}
								} else {
									keyMap[v.MetaID] = make(map[string]struct{})
								}

								if field, ok := metaKeyMap[key]; ok {
									idMetaMap[v.ProductID] = append(idMetaMap[v.ProductID], &product.MetaInfo{
										Id:    &v.MetaID,
										Key:   pointy.GetPointer(field),
										Value: pointy.GetPointer(v.MetaValue.String),
									})
								}
							}
						}
					}
				}
			}
		}

		idMediaMap := make(map[uint64][]*product.MediaInfo)
		productMediaEntityName := model.RpcEntityNames.ProductMedia
		if _, ok := subEntitySettingMap[productMediaEntityName]; ok {
			productMediaRepositoryName := model.RepositoryNames.ProductMedia
			subPreloadFields, hasSubPreloadFields := preloadMap[productMediaEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[productMediaRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				subFilterMap := make(map[string]map[string][]any)
				subFilterMap[model.ProductAttachmentRelationshipColumns.ObjectID] = map[string][]any{
					"in": ids,
				}
				subFilterMap[model.ProductAttachmentRelationshipColumns.ObjectType] = map[string][]any{
					"equalTo": {globalkey.PostTypeProduct},
				}
				subFilterMap[model.ProductAttachmentRelationshipColumns.AttachmentThumbnail] = map[string][]any{
					"equalTo": {1},
				}
				subSelectCols = append(subSelectCols, model.ProductAttachmentRelationshipColumns.ObjectID)
				var orderBy string = model.ProductAttachmentRelationshipColumns.AttachmentOrder
				list, _, err := l.svcCtx.CurrentProduct.GetMedia(l.ctx, model.M{
					"orderBy": orderBy,
					"select":  strings.Join(subSelectCols, ","),
				}, -1, subFilterMap)
				if err != nil {
					return nil, err
				}

				if len(list) > 0 {
					for _, v := range list {
						idMediaMap[v.ObjectID] = append(idMediaMap[v.ObjectID], &product.MediaInfo{
							Uid:       &v.AttachmentRelationshipID,
							Id:        pointy.GetPointer(strconv.FormatUint(v.AttachmentID, 10)),
							Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
							Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
							Uri:       &v.AttachmentSource,
							Url:       &v.AttachmentImageURL,
							AltText:   &v.AttachmentImageAlt,
							MetaData:  &v.AttachmentImageMeta,
						})
					}
				}
			}
		}

		for _, v := range res {
			var media []*product.MediaInfo
			if ms, ok := idMediaMap[v.ID]; ok {
				media = ms[:]
			}
			var meta []*product.MetaInfo
			if ms, ok := idMetaMap[v.ID]; ok {
				meta = ms[:]
			}
			var categories []*product.TermInfo
			if ts, ok := idCategoryMap[v.ID]; ok {
				categories = ts[:]
			}
			var tags []*product.TermInfo
			if ts, ok := idTagMap[v.ID]; ok {
				tags = ts[:]
			}
			var entries []*product.EntryInfo
			if es, ok := idEntryMap[v.ID]; ok {
				entries = es[:]
			}
			var attrs []*product.ProductAttrInfo
			if as, ok := idAttrMap[v.ID]; ok {
				attrs = as[:]
			}
			var specs []*product.ProductAttrInfo
			if as, ok := idSpecMap[v.ID]; ok {
				specs = as[:]
			}
			var variations []*product.ProductVariationInfo
			if vs, ok := idVariationMap[v.ID]; ok {
				variations = vs[:]
			}
			resp.List = append(resp.List, &product.ProductInfo{
				Id:          &v.ID,
				ParentId:    &v.ParentID,
				Title:       &v.Title,
				Slug:        &v.Slug,
				ProductCode: &v.ProductCode,
				Excerpt:     &v.Excerpt,
				Uri:         &v.GUID,
				Status:      pointy.GetPointer(uint32(v.Status)),
				CreatedAt:   pointy.GetPointer(modelx.FormatTime(v.ProductDate, "")),
				UpdatedAt:   pointy.GetPointer(modelx.FormatTime(v.ProductModifiedDate, "")),
				VirtualType: pointy.GetPointer(uint32(v.VirtualType)),
				Sort:        pointy.GetPointer(uint32(v.SortOrder)),
				CreatedBy:   &v.ProductAuthorID,
				Categories:  categories,
				Tags:        tags,
				Relations:   entries,
				Meta:        meta,
				Media:       media,
				Attrs:       attrs,
				Specs:       specs,
				Skus:        variations,
			})
		}
	}
	resp.Total = uint64(total)

	return resp, nil
}
